package my.download;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import my.download.pojo.Download10;
import my.download.util.ExcelUtils;
import net.bytebuddy.implementation.bytecode.Throw;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
import org.apache.hc.core5.http.ClassicHttpRequest;
import org.apache.hc.core5.http.ContentType;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.http.io.support.ClassicRequestBuilder;
import org.openqa.selenium.Cookie;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;


public class Application10 {

    private static final Logger log = LoggerFactory.getLogger(Application10.class);

    private static final ThreadPoolExecutor executor = new ThreadPoolExecutor(100, 100,
            1, TimeUnit.DAYS,
            new SynchronousQueue<>(),
            runnable -> {
                Thread thread = new Thread(runnable);
                thread.setDaemon(true);
                return thread;
            },
            new ThreadPoolExecutor.CallerRunsPolicy()
    );

    private static final ObjectMapper objectMapper = new ObjectMapper();
    private static final String url ="https://finance-ht-ccms.hxfintec.com/ccms-app/service/request/call.htm";

    public static void main(String[] args) throws IOException {
        System.setProperty("webdriver.chrome.driver", System.getProperty("user.dir") + "/" + "chromedriver.exe");
        WebDriver driver = new ChromeDriver();
        driver.get("https://finance-ht-ccms.hxfintec.com/ccms-app/fastDevelop/process.htm?code=login&fromUrl=http%3A%2F%2Ffinance-ht-ccms.hxfintec.com%2Fccms-app%2FfastDevelop%2Fprocess.htm");
        log.info("请登录后选择需要进行的操作：1-备注案件 2-下载案件文档 ");
        log.info("请输入：");
        Scanner sc = new Scanner(System.in);
        int type = sc.nextInt();
        List<String> lineList = Files.readAllLines(Path.of(System.getProperty("user.dir") + "/" + "line.txt"));
        Set<Cookie> cookies = driver.manage().getCookies();
        StringBuilder cookieStr = new StringBuilder();
        for (Cookie cookie : cookies) {
            cookieStr.append(cookie.getName()).append("=").append(cookie.getValue()).append(";");
        }
        driver.close();
        if (type == 1) {
            remark(cookieStr.substring(0, cookieStr.length() - 1), lineList);
        } else {
            download(cookieStr.substring(0, cookieStr.length() - 1), lineList);
        }
    }

    private static void download(String cookie, List<String> lineList) {
        String fileName = "导出-" + System.currentTimeMillis() + ".xlsx";
        String fullName = System.getProperty("user.dir") + "/" + fileName;
        Path path = Paths.get(fullName);
        try (CloseableHttpClient httpclient = HttpClients.custom()
                .setConnectionManager(
                        PoolingHttpClientConnectionManagerBuilder.create().build()
                )
                .setDefaultRequestConfig(RequestConfig.custom()
                        .setConnectionRequestTimeout(60, TimeUnit.SECONDS)
                        .setResponseTimeout(60, TimeUnit.SECONDS)
                        .build()
                )
                .build();
             OutputStream out = Files.newOutputStream(path)) {
            List<Download10> res = Collections.synchronizedList(new ArrayList<>());
            for (String businessLine: lineList) {
                if (businessLine == null || businessLine.isEmpty()) {
                    continue;
                }
                for (int page = 1; ; ) {
                    try {
                        JsonNode listResp = listCase(httpclient, cookie, page, businessLine);
                        JsonNode caseList = listResp.get("body").get("results");
                        if (caseList == null||caseList.isEmpty()){
                            break;
                        }
                        int totalPage = listResp.get("page").get("totalNum").asInt() / 100 + 1;
                        CountDownLatch countDownLatch = new CountDownLatch(caseList.size());
                        for (int i = 0; i < caseList.size(); i++) {
                            JsonNode data = caseList.get(i);
                            executor.execute(() -> {
                                try {
                                    String caseId = data.get("caseId").asText();
                                    String custNo = data.get("custNo").asText();
                                    Download10 item =  downCase(httpclient, cookie, businessLine, caseId, custNo);
                                    if (item != null) {
                                        res.add(item);
                                    }
                                } catch (Throwable e) {
                                    log.info("---", e);
                                }finally {
                                    countDownLatch.countDown();
                                }
                            });
                        }
                        countDownLatch.await();
                        if (caseList.size() < 100) {
                            break;
                        }
                        log.info("业务线[{}]下载进度[{}%]", businessLine, String.format("%.2f", (page * 100.0) / totalPage));
                        page++;
                    } catch (Throwable e) {
                        log.info("---", e);
                    }
                }
                log.info("业务线[{}]下载进度完成", businessLine);
            }
            String[][] headers = {
                    {"业务线", "businessLine"},
                    {"姓名", "name"},
                    {"账号", "account"},
                    {"合约手机", "phoneNo1"},
                    {"注册手机", "phoneNo2"},
                    {"案件金额", "caseAmt"},
                    {"未收本金", "acct6"},
                    {"当期逾期期数", "acct21"},
                    {"商品名称", "goodName"},
                    {"金融产品", "productName"},
                    {"入催日期", "incollDate"},
                    {"永久催收员", "everCollector"},
                    {"业务线分类", "businessLineDetail"},
            };
            ExcelUtils.exportExcel2007(fileName, headers, res, out);
        } catch (Throwable e) {
            log.error("下载案件异常", e);
            try {
                Files.deleteIfExists(path);
            } catch (IOException ignore) {}
        }
    }

    private static Download10 downCase(CloseableHttpClient httpclient, String cookie, String businessLine,
                                       String caseId, String custNo) {
        try {
            String infoResp = postReq(httpclient, cookie, getInfoReqBody(caseId));
            JsonNode infoData = getRealRespData(infoResp);
            JsonNode info = infoData.get("body").get("results").get(0);
            String userId = "aa";
            if (info == null) {
                return null;
            }
            String caseAmt = info.get("caseAmt") != null ? info.get("caseAmt").asText() : "";
            String account = info.get("acct1") != null ? info.get("acct1").asText() : "";
            String goodName = info.get("goodName") != null ? info.get("goodName").asText() : "";
            // 当期逾期期数
            String acct21 = info.get("acct21") != null ? info.get("acct21").asText() : "";
            String productName = info.get("productName") != null ? info.get("productName").asText() : "";
            String incollDate = info.get("incollDate") != null ? info.get("incollDate").asText() : "";
            String everCollector = info.get("everCollector") != null ? info.get("everCollector").asText() : "";
            // 业务线分类
            String businessLineDetail = info.get("businessLineDetail") != null ? info.get("businessLineDetail").asText() : "";
            // 未收本金
            String acct6 = info.get("acct6") != null ? info.get("acct6").asText() : "";
            String telResp = postReq(httpclient, cookie, getTelReqBody(custNo));
            JsonNode telData = getRealRespData(telResp);
            JsonNode telList = telData.get("body").get("results");
            String name = "", phoneNo1 = "", phoneNo2 = "";
            for (int j= 0; j < telList.size(); j++) {
                JsonNode telType = telList.get(j).get("telType");
                JsonNode telId = telList.get(j).get("telId");
                if (telType != null && telId != null) {
                    String telTypeStr = telType.asText();
                    if ("新手机".equals(telTypeStr)) {
                        String nameReqBody = postReq(httpclient, cookie, getNameReqBody(userId, caseId, telId.asText()));
                        JsonNode realRespData = getRealRespData(nameReqBody);
                        if (realRespData != null) {
                            JsonNode body = realRespData.get("body");
                            if (body != null && body.get("telName") != null) {
                                name = body.get("telName").asText();
                            }
                        }
                    } else if ("合约手机".equals(telTypeStr)) {
                        String phoneNoReqBody = postReq(httpclient, cookie, getPhoneNoReqBody(userId, caseId, telId.asText()));
                        JsonNode realRespData = getRealRespData(phoneNoReqBody).get("body");
                        if (name == null || name.isEmpty()) {
                            name = realRespData.get("telName") != null? realRespData.get("telName").asText():null;
                        }
                        phoneNo1 = realRespData.get("telNo").asText();
                    } else if ("注册手机".equals(telTypeStr)) {
                        String phoneNoReqBody = postReq(httpclient, cookie, getPhoneNoReqBody(userId, caseId, telId.asText()));
                        JsonNode realRespData = getRealRespData(phoneNoReqBody).get("body");
                        if (name == null || name.isEmpty()) {
                            name = realRespData.get("telName") != null ? realRespData.get("telName").asText() : null;
                        }
                        phoneNo2 = realRespData.get("telNo")!=null ? realRespData.get("telNo").asText():null;
                    }
                }
            }
            return new Download10(businessLine,
                    name, account, phoneNo1, phoneNo2, caseAmt, acct6, acct21,
                    goodName, productName, incollDate, everCollector, businessLineDetail
            );
        } catch (Throwable e) {
            log.error("下载案件[{}]异常", caseId, e);
        }
        return null;
    }

    private static void remark(String cookie, List<String> lineLIst) {
        try (CloseableHttpClient httpclient = HttpClients.createDefault()) {
            for (String businessLine : lineLIst) {
                if (businessLine == null || businessLine.isEmpty()) {
                    continue;
                }
                for (int page = 1; ; ) {
                    try {
                        JsonNode listResp = listCase(httpclient, cookie, page, businessLine);
                        JsonNode caseList = listResp.get("body").get("results");
                        if (caseList == null||caseList.isEmpty()){
                            break;
                        }
                        int totalPage = listResp.get("page").get("totalNum").asInt() / 100 + 1;
                        CountDownLatch countDownLatch = new CountDownLatch(caseList.size());
                        for (int i = 0; i < caseList.size(); i++) {
                            JsonNode caseInfo = caseList.get(i);
                            executor.execute(() -> {
                                try {
                                    remarkCase(httpclient, cookie, caseInfo);
                                } catch (Throwable e) {
                                    log.info("---", e);
                                }finally {
                                    countDownLatch.countDown();
                                }
                            });
                        }
                        countDownLatch.await();
                        log.info("业务线[{}]添加进度[{}%]", businessLine, String.format("%.2f", (page * 100.0) / totalPage));
                        if (caseList.size() < 100) {
                            break;
                        }
                        log.info("业务线[{}]备注进度[{}%]", businessLine, String.format("%.2f", (page * 100.0) / totalPage));
                        page++;
                    } catch (Throwable e) {
                        log.info("---", e);
                    }
                }
                log.info("业务线[{}]备注进度完成", businessLine);
            }
        } catch (Throwable e) {
            log.error("备注案件异常", e);
        }
    }

    private static void remarkCase(CloseableHttpClient httpClient, String cookie, JsonNode caseInfo) {
        if (caseInfo.get("caseId") == null) {
            return;
        }
        String caseId = caseInfo.get("caseId").asText();
        String collector = caseInfo.get("collector").asText();
        try {
            Random random = new Random();
            int type = random.nextInt(2);
            String remarkReqBody;
            if (type == 0) {
                remarkReqBody = getRemarkReqBody01(caseId, collector);
            } else {
                remarkReqBody = getRemarkReqBody02(caseId, collector);
            }
            String respStr = postReq(httpClient, cookie, remarkReqBody);
            JsonNode resp = objectMapper.readTree(respStr);
            JsonNode header = resp.get("scubeHeader");
            if (header != null) {
                JsonNode errorCode = header.get("errorCode");
                if (errorCode != null && "SUC".equals(errorCode.asText())) {
                    return;
                }
            }
            log.error("案件[{}]备注失败，resp=[{}]", caseId, respStr);
        } catch (Throwable e) {
            log.error("案件[{}]备注失败", caseId, e);
        }
    }

    private static String postReq(CloseableHttpClient httpClient, String cookie, String body) throws IOException {
        ClassicHttpRequest listReq = ClassicRequestBuilder.post(url)
                .addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36")
                .addHeader("Cookie", cookie)
                .setEntity(body, ContentType.APPLICATION_JSON)
                .build();
        return httpClient.execute(listReq, response -> EntityUtils.toString(response.getEntity()));
    }

    private static JsonNode listCase(CloseableHttpClient httpClient, String cookie, int page, String businessLine) throws IOException {

        String resp = postReq(httpClient, cookie, getListReqBody(page, businessLine));
        return getRealRespData(resp);
    }

    private static JsonNode getRealRespData(String respStr) throws JsonProcessingException {
        JsonNode respData = objectMapper.readTree(respStr);
        return objectMapper.readTree(respData.get("scubeBody").get("contextData").get("data").asText());
    }

    private static String getListReqBody(int page, String businessLine) {
        String reqBody = "{" +
                "    \"queryTable\": {" +
                "        \"scubeHeader\": {" +
                "            \"transCode\": \"queryListService/queryResult\"," +
                "            \"errorCode\": \"\"," +
                "            \"errorMsg\": \"\"" +
                "        }," +
                "        \"scubeBody\": {" +
                "            \"contextData\": {" +
                "                \"domainVilidate\": \"\"," +
                "                \"data\": {" +
                "                    \"head\": {}," +
                "                    \"body\": {" +
                "                        \"businessLine\": \"" + businessLine + "\"," +
                "                        \"path\": \"querylist_module/html/querylist_module.html\"," +
                "                        \"qlCode\": \"telConfMqManager\"" +
                "                    }," +
                "                    \"page\": {" +
                "                        \"pageNum\": " + page + "," +
                "                        \"pageSize\": 100" +
                "                    }," +
                "                    \"transCode\": \"queryListService/queryResult\"" +
                "                }" +
                "            }" +
                "        }" +
                "    }" +
                "}";
        return reqBody.replaceAll(" ", "");
    }

    private static String getInfoReqBody(String caseId) {
        String reqBody = "{" +
                "    \"queryTable\": {" +
                "        \"scubeHeader\": {" +
                "            \"transCode\": \"dynamicFormService/queryDetail\"," +
                "            \"errorCode\": \"\"," +
                "            \"errorMsg\": \"\"" +
                "        }," +
                "        \"scubeBody\": {" +
                "            \"contextData\": {" +
                "                \"domainVilidate\": \"\"," +
                "                \"data\": {" +
                "                    \"head\": {" +
                "                    }," +
                "                    \"body\": {" +
                "                        \"caseId\": \"" + caseId + "\"," +
                "                        \"dfCode\": \"caseInfo\"" +
                "                    }," +
                "                    \"transCode\": \"dynamicFormService/queryDetail\"" +
                "                }" +
                "            }" +
                "        }" +
                "    }" +
                "}";
        return reqBody.replaceAll(" ", "");
    }

    private static String getTelReqBody(String custNo) {
        String reqBody = "{" +
                "    \"queryTable\": {" +
                "        \"scubeHeader\": {" +
                "            \"transCode\": \"queryListService/queryResultAndModel\"," +
                "            \"errorCode\": \"\"," +
                "            \"errorMsg\": \"\"" +
                "        }," +
                "        \"scubeBody\": {" +
                "            \"contextData\": {" +
                "                \"domainVilidate\": \"\"," +
                "                \"data\": {" +
                "                    \"head\": {" +
                "                    }," +
                "                    \"body\": {" +
                "                        \"custNo\": \"" + custNo + "\"," +
                "                        \"qlCode\": \"tblCcmsBizCustTel\"" +
                "                    }," +
                "                    \"transCode\": \"queryListService/queryResultAndModel\"" +
                "                }" +
                "            }" +
                "        }" +
                "    }" +
                "}";
        return reqBody.replaceAll(" ", "");
    }

    private static String getNameReqBody(String userId, String caseId, String telId) {
        String reqBody = "{" +
                "    \"queryTable\": {" +
                "        \"scubeHeader\": {" +
                "            \"transCode\": \"caseSensitiveViewLog/saveLogByCustomerTelInfo\"," +
                "            \"errorCode\": \"\"," +
                "            \"errorMsg\": \"\"" +
                "        }," +
                "        \"scubeBody\": {" +
                "            \"contextData\": {" +
                "                \"domainVilidate\": \"\"," +
                "                \"data\": {" +
                "                    \"param\": {" +
                "                        \"head\": {" +
                "                        }," +
                "                        \"body\": {" +
                "                            \"viewField\": \"name\"," +
                "                            \"viewFieldName\": \"电话簿-姓名\"," +
                "                            \"caseId\": \"" + caseId + "\"," +
                "                            \"viewBy\": \"" + userId + "\"," +
                "                            \"custNo\": \"\"," +
                "                            \"telId\": \"" + telId + "\"," +
                "                            \"contactId\": \"\"" +
                "                        }" +
                "                    }" +
                "                }" +
                "            }" +
                "        }" +
                "    }" +
                "}";
        return reqBody.replaceAll(" ", "");
    }

    private static String getPhoneNoReqBody(String userId, String caseId, String telId) {
        String reqBody = "{" +
                "    \"queryTable\": {" +
                "        \"scubeHeader\": {" +
                "            \"transCode\": \"caseSensitiveViewLog/saveLogByCustomerTelInfo\"," +
                "            \"errorCode\": \"\"," +
                "            \"errorMsg\": \"\"" +
                "        }," +
                "        \"scubeBody\": {" +
                "            \"contextData\": {" +
                "                \"domainVilidate\": \"\"," +
                "                \"data\": {" +
                "                    \"param\": {" +
                "                        \"head\": {" +
                "                        }," +
                "                        \"body\": {" +
                "                            \"viewField\": \"tel_no\"," +
                "                            \"viewFieldName\": \"电话簿-电话号码\"," +
                "                            \"caseId\": \"" + caseId + "\"," +
                "                            \"viewBy\": \"" + userId + "\"," +
                "                            \"custNo\": \"\"," +
                "                            \"telId\": \""+ telId + "\"," +
                "                            \"contactId\": \"\"" +
                "                        }" +
                "                    }" +
                "                }" +
                "            }" +
                "        }" +
                "    }" +
                "}";
        return reqBody.replaceAll(" ", "");
    }

    private static String getRemarkReqBody01(String caseId, String collector) {
        String reqBody = "{" +
                "    \"queryTable\": {" +
                "        \"scubeHeader\": {" +
                "            \"transCode\": \"caseRemark/doExcute\"," +
                "            \"errorCode\": \"\"," +
                "            \"errorMsg\": \"\"" +
                "        }," +
                "        \"scubeBody\": {" +
                "            \"contextData\": {" +
                "                \"domainVilidate\": \"\"," +
                "                \"data\": {" +
                "                    \"param\": {" +
                "                        \"head\": {" +
                "                            " +
                "                        }," +
                "                        \"body\": {" +
                "                            \"collector\": \""+collector+"\"," +
                "                            \"caseId\": \"" + caseId + "\"," +
                "                            \"remark\": \"通话中\"," +
                "                            \"userStatus\": \"P\"," +
                "                            \"colResultB\": \"DJ\"," +
                "                            \"colType\": \"M\"" +
                "                        }" +
                "                    }" +
                "                }" +
                "            }" +
                "        }" +
                "    }" +
                "}";
        return reqBody.replaceAll(" ", "");
    }

    private static String getRemarkReqBody02(String caseId,String collector) {
        String reqBody = "{" +
                "    \"queryTable\": {" +
                "        \"scubeHeader\": {" +
                "            \"transCode\": \"caseRemark/doExcute\"," +
                "            \"errorCode\": \"\"," +
                "            \"errorMsg\": \"\"" +
                "        }," +
                "        \"scubeBody\": {" +
                "            \"contextData\": {" +
                "                \"domainVilidate\": \"\"," +
                "                \"data\": {" +
                "                    \"param\": {" +
                "                        \"head\": {" +
                "                        }," +
                "                        \"body\": {" +
                "                            \"collector\": \""+collector+"\"," +
                "                            \"caseId\": \"" + caseId + "\"," +
                "                            \"remark\": \"无法接通\"," +
                "                            \"userStatus\": \"L\"," +
                "                            \"colResultB\": \"MY\"," +
                "                            \"colType\": \"M\"" +
                "                        }" +
                "                    }" +
                "                }" +
                "            }" +
                "        }" +
                "    }" +
                "}";
        return reqBody.replaceAll(" ", "");
    }
}
